﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;

namespace OpenSearch.Client
{
    /// <summary>
    /// This class will generate URI's from search terms and reverse them
    /// </summary>
    internal static class OpenSearchUriBuilder
    {
        public const string SearchTerms = @"{searchTerms}";

        public static Uri CreateUriFromTerms(Uri openSearchUrl, string terms)
        {
            var paramName = GetSearchQueryParamName(openSearchUrl.Query);

            var uri = new Uri(openSearchUrl, new Uri(openSearchUrl.AbsolutePath + string.Format("?{0}={1}", paramName, Uri.EscapeDataString(terms ?? string.Empty)), UriKind.Relative));
            
            return uri;
        }

        public static string GetTermsFromUri(Uri openSearchUrl, Uri requestedUrl)
        {
            
            if (requestedUrl.Host == openSearchUrl.Host)
            {
                var stringToSearch = requestedUrl.Query + requestedUrl.Fragment;
                if (string.IsNullOrWhiteSpace(stringToSearch))
                {
                    return null;
                }
                // base matches, get the terms
                var paramName = GetSearchQueryParamName(openSearchUrl.Query);
                
                // see requested url has the search param

                var terms = GetQueryParameters(stringToSearch);

                // Some engines, like google, may add-on the query after a #
                var term = terms.LastOrDefault(t => t.Item1 == paramName);
                
                if (term != null)
                    return UrlDecode(term.Item2 ?? string.Empty);
            }
            return null;
        }



        /// <summary>
        /// UrlDecodes a string without requiring System.Web
        /// </summary>
        /// <param name="text">String to decode.</param>
        /// <returns>decoded string</returns>
        public static string UrlDecode(string text)
        {
            // From http://www.west-wind.com/weblog/posts/617930.aspx
            // pre-process for + sign space formatting since System.Uri doesn't handle it
            // plus literals are encoded as %2b normally so this should be safe
            text = text.Replace("+", " ");
            return Uri.UnescapeDataString(text);
        }


        private static string GetSearchQueryParamName(string queryString)
        {
            var terms = GetQueryParameters(queryString);
            return terms.First(tup => SearchTerms.Equals(tup.Item2, StringComparison.Ordinal)).Item1;
        }

        private static IEnumerable<Tuple<string,string>> GetQueryParameters(string queryString)
        {
            if (queryString.StartsWith("?"))
                queryString = queryString.Remove(0, 1);

            var parameterPairs = queryString.Split('&');

            var d = from pair in parameterPairs
                    let t = pair.Split('=')
                    where t.Length == 2 // filter out empty ones
                    select Tuple.Create(t[0], t[1]);

            return d;
        }
    }
}
